name: Wheels
on:
  workflow_dispatch:
  schedule:
    - cron: "0 8 * * *"

permissions: read-all

jobs:

  Build-Wheels:
    timeout-minutes: 60

    runs-on: [self-hosted, CPU]
    permissions:
      id-token: write
      contents: read

    steps:

      - name: Prune stale docker containers
        run: |
          # If cibuildwheel crashes (or, say, is OOM-killed), it leaves behind a
          # docker container.  Eventually these consume all the disk space on
          # this machine.
          docker container prune -f

      - name: Checkout
        uses: actions/checkout@v4

      # The LATEST_DATE here should be kept in sync with the one in Patch setup.py
      - id: check-version
        name: Check latest version
        run: |
          export PACKAGE_DATE=$(python3 -m pip install --user --index-url https://aiinfra.pkgs.visualstudio.com/PublicPackages/_packaging/Triton-Nightly/pypi/simple/ --dry-run triton-nightly== |& grep -oP '(?<=, )[0-9\.]+dev[0-9]+(?=\))' | grep -oP '(?<=dev)[0-9]+')
          export LATEST_DATE=$(TZ=UTC0 git show --quiet --date='format-local:%Y%m%d%H%M%S' --format="%cd")
          if cmp -s <(echo $PACKAGE_DATE) <(echo $LATEST_DATE); then
            echo "new_commit=false" >> "$GITHUB_OUTPUT"
          else
            echo "new_commit=true" >> "$GITHUB_OUTPUT"
          fi

      - name: Patch setup.py
        if: ${{ steps.check-version.outputs.new_commit == 'true' }}
        run: |
          echo "" >> python/setup.cfg
          echo "[build_ext]" >> python/setup.cfg
          echo "base-dir=/project" >> python/setup.cfg

      - name: Build wheels
        if: ${{ steps.check-version.outputs.new_commit == 'true' }}
        run: |
          export LATEST_DATE=$(TZ=UTC0 git show --quiet --date='format-local:%Y%m%d%H%M%S' --format="%cd")
          # Pass MAX_JOBS=4 because, at time of writing, the VM "only" has 32GB
          # of RAM and OOMs while building if we give it the default number of
          # workers (2 * NUM_CPUs).
          #
          # Sadly, I couldn't make TRITON_BUILD_WITH_CLANG_LLD=1 work.  The
          # manylinux image has a relatively recent gcc (v10, released 2020),
          # but its clang is ancient, v3.4, released in 2014 (!).  I tried
          # installing the prebuilt clang 10 binary distributed by LLVM, and I
          # quickly ran into Linux DLL hell.  I give up, for now.  Perhaps
          # manylinux_x_y will save us; I didn't try.
          export CIBW_ENVIRONMENT="MAX_JOBS=4 TRITON_WHEEL_NAME=triton-nightly TRITON_WHEEL_VERSION_SUFFIX=-$LATEST_DATE"
          export CIBW_MANYLINUX_X86_64_IMAGE="quay.io/pypa/manylinux2014_x86_64:latest"
          #export CIBW_MANYLINUX_PYPY_X86_64_IMAGE="quay.io/pypa/manylinux2014_x86_64:latest"
          export CIBW_BEFORE_BUILD="pip install cmake;"
          export CIBW_SKIP="cp{35,36}-*"
          export CIBW_BUILD="cp3*-manylinux_x86_64"
          python3 -m cibuildwheel python --output-dir wheelhouse

      - name: Install Azure CLI
        if: ${{ steps.check-version.outputs.new_commit == 'true' }}
        run: |
          curl -sL https://aka.ms/InstallAzureCLIDeb | sudo bash

      - name: Azure login
        if: ${{ steps.check-version.outputs.new_commit == 'true' }}
        uses: azure/login@v1
        with:
          client-id: ${{ secrets.AZURE_CLIENT_ID }}
          tenant-id: ${{ secrets.AZURE_TENANT_ID }}
          subscription-id: ${{ secrets.AZURE_SUBSCRIPTION_ID }}

      - id: generate-token
        name: Generate token
        if: ${{ steps.check-version.outputs.new_commit == 'true' }}
        run: |
          AZ_TOKEN=$(az account get-access-token --query accessToken)
          echo "::add-mask::$AZ_TOKEN"
          echo "access_token=$AZ_TOKEN" >> "$GITHUB_OUTPUT"

      - name: Publish wheels to Azure DevOps
        if: ${{ steps.check-version.outputs.new_commit == 'true' }}
        run: |
          python3 -m pip install twine
          python3 -m twine upload -r Triton-Nightly -u TritonArtifactsSP -p ${{ steps.generate-token.outputs.access_token }} --config-file utils/nightly.pypirc --non-interactive --verbose wheelhouse/*

      - name: Azure Logout
        if: ${{ steps.check-version.outputs.new_commit == 'true' && (success() || failure()) }}
        run: |
          az logout
          az cache purge
          az account clear
